﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using EnvDTE80;
using System.IO;
using LinqToEdmx;
using System.Xml.Linq;

namespace CslaDesigner
{
    [System.Runtime.InteropServices.ComVisible(true)]
    public partial class DesignerBox : UserControl
    {
        public DesignerBox()
        {
            InitializeComponent();
        }

        #region 属性 变量
        public DTE2 DTE
        {
            get;
            set;
        }
        Edmx edmx;

        XName xnFriendlyname = XName.Get("CslaFriendlyName", "http://schemas.tempuri.com/CslaPropertyExtension");
        XName xnCslaItemName = XName.Get("CslaItemName", "http://schemas.tempuri.com/CslaEntityExtension");
        XName xnCslaCollectionName = XName.Get("CslaCollectionName", "http://schemas.tempuri.com/CslaEntityExtension");
        XName xnCslaClassTemplate = XName.Get("CslaClassTemplate", "http://schemas.tempuri.com/CslaEntityExtension");


        string _EditableRoot = "EditableRoot";
        string _ReadOnlyRootList = "ReadOnlyRootList";

        string _List = "List";
        string _Info = "Info";
        string _Edit = "Edit";

        string edmxFilename;
        #endregion

        #region 方法
        public void RefreshUI()
        {
            if (DTE.ActiveDocument != null)
            {
                string filefullname = DTE.ActiveDocument.FullName;
                FileInfo fi = new FileInfo(filefullname);
                if (fi.Extension.Equals(".edmx", StringComparison.OrdinalIgnoreCase))
                {
                    InitData(fi);
                }
            }
        }

        private void InitData(FileInfo fileinfo)
        {
            SetControls(true);
            toolStripTextBox1.Text = fileinfo.Name;
            edmx = Edmx.Load(fileinfo.FullName);
            edmxFilename = fileinfo.FullName;

            DictList dictlist = new DictList();
            IEnumerable<LinqToEdmx.Model.Conceptual.ConceptualSchema> cs = edmx.GetItems<LinqToEdmx.Model.Conceptual.ConceptualSchema>();

            foreach (LinqToEdmx.Model.Conceptual.ConceptualSchema q in cs)
            {
                foreach (LinqToEdmx.Model.Conceptual.EntityType et in q.EntityTypes)
                {
                    string keyE = et.Name.ToLower();
                    if (dictlist.Count(e => e.Key == keyE) == 0)
                        dictlist.Add(new DictInfo() { Key = keyE, Name = et.Name, DisplayName = "" });

                    foreach (LinqToEdmx.Model.Conceptual.EntityProperty p in et.Properties)
                    {
                        string keyP = string.Format("{0}.{1}", keyE, p.Name.ToLower());
                        string friendlyname = string.Empty;
                        var eFn = ((System.Xml.Linq.XElement)p).Elements(xnFriendlyname).FirstOrDefault();
                        if (eFn != null)
                        {
                            friendlyname = eFn.Value;
                        }
                        if (dictlist.Count(e => e.Key == keyP) == 0)
                            dictlist.Add(new DictInfo() { Key = keyP, Name = p.Name, DisplayName = friendlyname });
                    }
                }
            }
            gridDict.DataSource = dictlist;
        }

        private void SetControls(bool enabled)
        {
            toolStrip1.Enabled = panel1.Enabled = enabled;
        }

        private void SaveDictionary()
        {
            using (SaveFileDialog savefiledialog = new SaveFileDialog())
            {
                savefiledialog.Filter = "XML文件(*.XML)|*.XML";
                if (savefiledialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    XmlManager.Save(savefiledialog.FileName, gridDict.DataSource as DictList);
                    MessageBox.Show("保存成功");
                }
            }
        }

        /// <summary>
        /// 打开字典
        /// </summary>
        private void OpernDictionary()
        {
            OpenFileDialog openfiledialog = new OpenFileDialog();
            openfiledialog.Filter = "XML文件(*.XML)|*.XML";
            if (openfiledialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                try
                {
                    DictList dictlist = XmlManager.Load(typeof(DictList), openfiledialog.FileName) as DictList;
                    DictList maindict = gridDict.DataSource as DictList;
                    foreach (var item in maindict)
                    {
                        var dictfromfile = dictlist.Where(e => e.Key == item.Key).FirstOrDefault();
                        if (dictfromfile != null)
                        {
                            item.DisplayName = dictfromfile.DisplayName;
                            item.Name = dictfromfile.Name;
                        }
                    }
                    gridDict.DataSource = null;
                    gridDict.DataSource = maindict;
                }
                catch
                {
                    MessageBox.Show("读取XML文件失败");
                }
            }
        }

        /// <summary>
        /// 保存EDMX
        /// </summary>
        private void RenameEdmx()
        {
            string ConceptualModelsNamespace;

            IEnumerable<LinqToEdmx.Model.Conceptual.ConceptualSchema> conceptualschemas = this.edmx.GetItems<LinqToEdmx.Model.Conceptual.ConceptualSchema>();
            #region ConceptualSchema
            ConceptualModelsNamespace = conceptualschemas.First().Namespace;
            foreach (LinqToEdmx.Model.Conceptual.ConceptualSchema conceptualschema in conceptualschemas)
            {
                #region EntityContainer
                foreach (var entitycontainer in conceptualschema.EntityContainers)
                {
                    foreach (var entityset in entitycontainer.EntitySets)
                    {
                        string value = GetName(entityset.Name.ToLower());
                        entityset.Name = string.IsNullOrEmpty(value) ? entityset.Name : value;
                        entityset.EntityType = string.IsNullOrEmpty(value) ? entityset.Name : GetTypeName(conceptualschema.Namespace, value);
                    }
                    foreach (var associationset in entitycontainer.AssociationSets)
                    {
                        foreach (var end in associationset.Ends)
                        {
                            string value = GetName(end.EntitySet.ToLower());
                            end.EntitySet = string.IsNullOrEmpty(value) ? end.EntitySet : value;
                        }
                    }
                }
                #endregion

                #region EntityType
                foreach (var entitytype in conceptualschema.EntityTypes)
                {
                    string value = GetName(entitytype.Name.ToLower());
                    entitytype.Name = string.IsNullOrEmpty(value) ? entitytype.Name : value;
                    #region PropertyRef
                    foreach (var PropertyRef in entitytype.Key.PropertyRefs)
                    {
                        string valkey = GetName(GetTypeName(entitytype.Name, PropertyRef.Name).ToLower());
                        PropertyRef.Name = string.IsNullOrEmpty(valkey) ? PropertyRef.Name : valkey;
                    }
                    #endregion
                    #region Property
                    foreach (var entityproperty in entitytype.Properties)
                    {
                        string valp = GetName(GetTypeName(entitytype.Name, entityproperty.Name).ToLower());
                        entityproperty.Name = string.IsNullOrEmpty(valp) ? entityproperty.Name : valp;
                        string strdisplayname = GetDisplayName(GetTypeName(entitytype.Name, entityproperty.Name).ToLower());
                        if (!string.IsNullOrEmpty(strdisplayname))
                        {
                            if (entityproperty.Documentation != null && entityproperty.Documentation.Summary != null)
                            {
                                entityproperty.Documentation = null;
                            }
                            var eFn = ((System.Xml.Linq.XElement)entityproperty).Elements(xnFriendlyname).FirstOrDefault();
                            if (eFn != null)
                            {
                                eFn.Value = strdisplayname;
                            }
                            else
                            {
                                var eP = ((System.Xml.Linq.XElement)entityproperty);
                                eP.Add(XElement.Parse(string.Format(@"<a:CslaFriendlyName xmlns:a=""http://schemas.tempuri.com/CslaPropertyExtension"">{0}</a:CslaFriendlyName>", strdisplayname)));
                            }
                            
                            //else
                            //{
                            //    LinqToEdmx.Model.Conceptual.Documentation nd = new LinqToEdmx.Model.Conceptual.Documentation();
                            //    entityproperty.Documentation = nd;
                            //    nd.Summary = (LinqToEdmx.Model.Conceptual.Text)new XElement(XName.Get("Summary", "")) { Value = strdisplayname };
                            //}
                        }
                    }
                    #endregion
                    #region NavigationProperty
                    foreach (var navigationproperty in entitytype.NavigationProperties)
                    {
                        string valp = GetName(navigationproperty.Name.ToLower());
                        navigationproperty.Name = string.IsNullOrEmpty(valp) ? navigationproperty.Name : valp;
                    }
                    #endregion
                }

                #region Association
                foreach (var association in conceptualschema.Associations)
                {
                    #region End
                    foreach (var end in association.Ends)
                    {
                        string value = GetName(GetClassName(conceptualschema.Namespace, end.Type).ToLower());
                        end.Type = string.IsNullOrEmpty(value) ? end.Type : GetTypeName(conceptualschema.Namespace, value);
                    }
                    #endregion
                    #region Principal
                    foreach (var PropertyRef in association.ReferentialConstraint.Principal.PropertyRefs)
                    {
                        string valkey = GetName(GetTypeName(association.ReferentialConstraint.Principal.Role, PropertyRef.Name).ToLower());
                        PropertyRef.Name = string.IsNullOrEmpty(valkey) ? PropertyRef.Name : valkey;
                    }
                    #endregion
                    #region Dependent
                    foreach (var PropertyRef in association.ReferentialConstraint.Dependent.PropertyRefs)
                    {
                        string valkey = GetName(GetTypeName(association.ReferentialConstraint.Dependent.Role, PropertyRef.Name).ToLower());
                        PropertyRef.Name = string.IsNullOrEmpty(valkey) ? PropertyRef.Name : valkey;
                    }
                    #endregion
                }
                #endregion

                #endregion
            }
            #endregion

            IEnumerable<LinqToEdmx.Map.EntityContainerMapping> entitycontainermappings = this.edmx.GetItems<LinqToEdmx.Map.EntityContainerMapping>();
            #region EntityContainerMapping
            foreach (var entitycontainermapping in entitycontainermappings)
            {
                foreach (var entitysetmapping in entitycontainermapping.EntitySetMappings)
                {
                    string value = GetName(entitysetmapping.Name.ToLower());
                    entitysetmapping.Name = string.IsNullOrEmpty(value) ? entitysetmapping.Name : value;
                    foreach (var entitytypemapping in entitysetmapping.EntityTypeMappings)
                    {
                        string val = GetName(GetClassName(ConceptualModelsNamespace, entitytypemapping.TypeName).ToLower());
                        entitytypemapping.TypeName = string.IsNullOrEmpty(value) ? entitytypemapping.TypeName : GetTypeName(ConceptualModelsNamespace, value);
                        foreach (var mappingfragment in entitytypemapping.MappingFragments)
                        {
                            foreach (var ScalarProperty in mappingfragment.ScalarProperties)
                            {
                                string valkey = GetName(GetTypeName(mappingfragment.StoreEntitySet, ScalarProperty.Name).ToLower());
                                ScalarProperty.Name = string.IsNullOrEmpty(valkey) ? ScalarProperty.Name : valkey;
                            }
                        }

                    }
                }
            }
            #endregion

            IEnumerable<LinqToEdmx.Designer.EntityTypeShape> entitytypeshapes = this.edmx.GetItems<LinqToEdmx.Designer.EntityTypeShape>();
            #region EntityTypeShape
            foreach (var entitytypeshape in entitytypeshapes)
            {
                string val = GetName(GetClassName(ConceptualModelsNamespace, entitytypeshape.EntityType).ToLower());
                entitytypeshape.EntityType = string.IsNullOrEmpty(val) ? entitytypeshape.EntityType : GetTypeName(ConceptualModelsNamespace, val);
            }
            #endregion

            edmx.Save(edmxFilename);
        }

        /// <summary>
        /// 以Storage中的最大长度 设置Conceptual的最大长度
        /// </summary>
        private void SetMaxLength()
        {
            //定义一个字典来存放Storage中表字段的字段长度
            Dictionary<string, object> dctMaxLength = new Dictionary<string, object>();
            IEnumerable<LinqToEdmx.Model.Storage.StorageSchema> ss = edmx.GetItems<LinqToEdmx.Model.Storage.StorageSchema>();

            foreach (LinqToEdmx.Model.Storage.StorageSchema s in ss)
            {
                foreach (LinqToEdmx.Model.Storage.EntityTypeStore ets in s.EntityTypeStores)
                {
                    foreach (LinqToEdmx.Model.Storage.EntityProperty p in ets.Properties)
                    {
                        if (p.MaxLength != null)
                            dctMaxLength.Add(string.Format("{0}.{1}", ets.Name, p.Name).ToLower(), p.MaxLength);
                    }
                }
            }

            IEnumerable<LinqToEdmx.Model.Conceptual.ConceptualSchema> cs = this.edmx.GetItems<LinqToEdmx.Model.Conceptual.ConceptualSchema>();
            foreach (LinqToEdmx.Model.Conceptual.ConceptualSchema q in cs)
            {
                foreach (LinqToEdmx.Model.Conceptual.EntityType et in q.EntityTypes)
                {
                    foreach (LinqToEdmx.Model.Conceptual.EntityProperty p in et.Properties)
                    {
                        string key = string.Format("{0}.{1}", et.Name, p.Name).ToLower();
                        if (dctMaxLength.ContainsKey(key))
                            p.MaxLength = dctMaxLength[key];
                    }
                }
            }

            edmx.Save(edmxFilename);
        }

        /// <summary>
        /// 修改EDM中实体的Csla模板类型
        /// </summary>
        private void SetTemplate()
        {
            if (string.IsNullOrEmpty(toolStripComboBox1.Text))
                return;
            string strclasstemplate = toolStripComboBox1.Text;

            IEnumerable<LinqToEdmx.Model.Conceptual.ConceptualSchema> conceptualschemas = this.edmx.GetItems<LinqToEdmx.Model.Conceptual.ConceptualSchema>();
            foreach (LinqToEdmx.Model.Conceptual.ConceptualSchema conceptualschema in conceptualschemas)
            {
                foreach (var entitytype in conceptualschema.EntityTypes)
                {
                    var XElementEntityType = (System.Xml.Linq.XElement)entitytype;
                    var cslaitemname = XElementEntityType.Element(xnCslaItemName);
                    var cslacollectionname = XElementEntityType.Element(xnCslaCollectionName);
                    var cslaclasstemplate = XElementEntityType.Element(xnCslaClassTemplate);

                    string stritemname;
                    string strcollectionname;

                    if (strclasstemplate.Equals(_EditableRoot))
                    {
                        stritemname = string.Format("{0}{1}", entitytype.Name, _Edit);
                    }
                    else
                    {
                        stritemname = string.Format("{0}{1}", entitytype.Name, _Info);
                    }
                    strcollectionname = string.Format("{0}{1}", entitytype.Name, _List);

                    #region CslaItemName
                    if (cslaitemname != null)
                    {
                        cslaitemname.Value = stritemname;
                    }
                    else
                    {
                        XElementEntityType.Add(XElement.Parse(string.Format(@"<a:CslaItemName xmlns:a=""http://schemas.tempuri.com/CslaEntityExtension"">{0}</a:CslaItemName>", stritemname)));
                    }
                    #endregion
                    #region CslaCollectionName
                    if (cslacollectionname != null)
                    {
                        cslacollectionname.Value = strcollectionname;
                    }
                    else
                    {
                        XElementEntityType.Add(XElement.Parse(string.Format(@"<a:CslaCollectionName xmlns:a=""http://schemas.tempuri.com/CslaEntityExtension"">{0}</a:CslaCollectionName>", strcollectionname)));
                    }
                    #endregion
                    #region CslaClassTemplate
                    if (cslaclasstemplate != null)
                    {
                        cslaclasstemplate.Value = strclasstemplate;
                    }
                    else
                    {
                        XElementEntityType.Add(XElement.Parse(string.Format(@"<a:CslaClassTemplate xmlns:a=""http://schemas.tempuri.com/CslaEntityExtension"">{0}</a:CslaClassTemplate>", strclasstemplate)));
                    }
                    #endregion
                }
            }
            edmx.Save(edmxFilename);
        }

        private string GetName(string key)
        {
            return GetValue(key, "Name");
        }

        private string GetDisplayName(string key)
        {
            return GetValue(key, "DisplayName");
        }

        private string GetValue(string key, string col)
        {
            DictList MainDict = gridDict.DataSource as DictList;
            string res;
            switch (col)
            {
                case "Name":
                    res = MainDict.Where(e => e.Key == key).Select(e => e.Name).FirstOrDefault().ToSafeStr();
                    break;

                case "DisplayName":
                    res = MainDict.Where(e => e.Key == key).Select(e => e.DisplayName).FirstOrDefault().ToSafeStr();
                    break;

                default:
                    res = string.Empty;
                    break;
            }
            return res;
        }

        private string GetTypeName(string ns, string cn)
        {
            return string.Format("{0}.{1}", ns, cn);
        }

        private string GetClassName(string ns, string fullname)
        {
            return fullname.Replace(ns, "").Replace(".", "");
        }
        #endregion

        #region 事件

        /// <summary>
        /// 保存字典
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSave_Click(object sender, EventArgs e)
        {
            SaveDictionary();
        }

        /// <summary>
        /// 打开字典按钮点击
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOpenDict_Click(object sender, EventArgs e)
        {
            OpernDictionary();
        }

        /// <summary>
        /// 重命名
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRename_Click(object sender, EventArgs e)
        {
            RenameEdmx();
        }

        /// <summary>
        /// 设置长度
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSetLength_Click(object sender, EventArgs e)
        {
            SetMaxLength();
        }

        /// <summary>
        /// 修改Csla模板类型
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSetTemplate_Click(object sender, EventArgs e)
        {
            SetTemplate();
        }
        #endregion


    }
}
